home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / SCRIPTS / TKCOND.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  10KB  |  361 lines

  1. /*
  2.  * tkcond.c
  3.  *
  4.  * Eric Youngdale was the original author of xconfig.
  5.  * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
  6.  *
  7.  * This file takes the tokenized statement list and transforms 'if ...'
  8.  * statements.  For each simple statement, I find all of the 'if' statements
  9.  * that enclose it, and attach the aggregate conditionals of those 'if'
  10.  * statements to the cond list of the simple statement.
  11.  *
  12.  * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
  13.  * - Steam-clean this file.  I tested this by generating kconfig.tk for
  14.  *   every architecture and comparing it character-for-character against
  15.  *   the output of the old tkparse.
  16.  *
  17.  * TO DO:
  18.  * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
  19.  *   you are interested in working on the replacement.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "tkparse.h"
  27.  
  28.  
  29.  
  30. /*
  31.  * Transform op_variable to op_kvariable.
  32.  *
  33.  * This works, but it's gross, speed-wise.  It would benefit greatly
  34.  * from a simple hash table that maps names to cfg.
  35.  *
  36.  * Note well: this is actually better than the loop structure xconfig
  37.  * has been staggering along with for three years, which performs
  38.  * this whole procedure inside *another* loop on active conditionals.
  39.  */
  40. void transform_to_kvariable( struct kconfig * scfg )
  41. {
  42.     struct kconfig * cfg;
  43.  
  44.     for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
  45.     {
  46.     struct condition * cond;
  47.  
  48.     for ( cond = cfg->cond; cond != NULL; cond = cond->next )
  49.     {
  50.         if ( cond->op == op_variable )
  51.         {
  52.         /* Here's where it gets DISGUSTING. */
  53.         struct kconfig * cfg1;
  54.  
  55.         for ( cfg1 = scfg; cfg1 != NULL; cfg1 = cfg1->next )
  56.         {
  57.             if ( cfg1->token == token_bool
  58.             ||   cfg1->token == token_choice_item
  59.             ||   cfg1->token == token_dep_tristate
  60.             ||   cfg1->token == token_hex
  61.             ||   cfg1->token == token_int
  62.             ||   cfg1->token == token_string
  63.             ||   cfg1->token == token_tristate )
  64.             {
  65.             if ( strcmp( cond->str, cfg1->optionname ) == 0 )
  66.             {
  67.                 cond->op  = op_kvariable;
  68.                 cond->str = NULL;
  69.                 cond->cfg = cfg1;
  70.                 break;
  71.             }
  72.             }
  73.         }
  74.         }
  75.  
  76. #if 0
  77.         /*
  78.          * Maybe someday this will be useful, but right now it
  79.          * gives a lot of false positives on files like
  80.          * drivers/video/Config.in that are meant for more
  81.          * than one architecture.  Turn it on if you want to play
  82.          * with it though; it does work.  -- mec
  83.          */
  84.         if ( cond->op == op_variable )
  85.         {
  86.         if ( strcmp( cond->str, "ARCH"       ) != 0
  87.         &&   strcmp( cond->str, "CONSTANT_Y" ) != 0
  88.         &&   strcmp( cond->str, "CONSTANT_M" ) != 0
  89.         &&   strcmp( cond->str, "CONSTANT_N" ) != 0 )
  90.         {
  91.             fprintf( stderr, "warning: $%s used but not defined\n",
  92.             cond->str );
  93.         }
  94.         }
  95. #endif
  96.     }
  97.     }
  98. }
  99.  
  100.  
  101.  
  102. /*
  103.  * Make a new condition chain by joining the current condition stack with
  104.  * the "&&" operator for glue.
  105.  */
  106. struct condition * join_condition_stack( struct condition * conditions [],
  107.     int depth )
  108. {
  109.     struct condition * cond_list;
  110.     struct condition * cond_last;
  111.     int i;
  112.  
  113.     cond_list = cond_last = NULL;
  114.     for ( i = 0; i < depth; i++ )
  115.     {
  116.     struct condition * cond;
  117.     struct condition * cnew;
  118.  
  119.     /* add a '(' */
  120.     cnew = malloc( sizeof(*cnew) );
  121.     memset( cnew, 0, sizeof(*cnew) );
  122.     cnew->op = op_lparen;
  123.     if ( cond_last == NULL )
  124.         { cond_list = cond_last = cnew; }
  125.     else
  126.         { cond_last->next = cnew; cond_last = cnew; }
  127.  
  128.     /* duplicate the chain */
  129.     for ( cond = conditions [i]; cond != NULL; cond = cond->next )
  130.     {
  131.         cnew            = malloc( sizeof(*cnew) );
  132.         cnew->next      = NULL;
  133.         cnew->op        = cond->op;
  134.         cnew->str       = cond->str ? strdup( cond->str ) : NULL;
  135.         cnew->cfg       = cond->cfg;
  136.         cond_last->next = cnew;
  137.         cond_last       = cnew;
  138.     }
  139.  
  140.     /* add a ')' */
  141.     cnew = malloc( sizeof(*cnew) );
  142.     memset( cnew, 0, sizeof(*cnew) );
  143.     cnew->op = op_rparen;
  144.     cond_last->next = cnew;
  145.     cond_last = cnew;
  146.  
  147.     /* if i have another condition, add an '&&' operator */
  148.     if ( i < depth - 1 )
  149.     {
  150.         cnew = malloc( sizeof(*cnew) );
  151.         memset( cnew, 0, sizeof(*cnew) );
  152.         cnew->op = op_and;
  153.         cond_last->next = cnew;
  154.         cond_last = cnew;
  155.     }
  156.     }
  157.  
  158.     /*
  159.      * Remove duplicate conditions.
  160.      */
  161.     {
  162.     struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
  163.  
  164.     for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
  165.     {
  166.         if ( cond1->op == op_lparen )
  167.         {
  168.         cond1b = cond1 ->next; if ( cond1b == NULL ) break;
  169.         cond1c = cond1b->next; if ( cond1c == NULL ) break;
  170.         cond1d = cond1c->next; if ( cond1d == NULL ) break;
  171.         cond1e = cond1d->next; if ( cond1e == NULL ) break;
  172.         cond1f = cond1e->next; if ( cond1f == NULL ) break;
  173.  
  174.         if ( cond1b->op == op_kvariable
  175.         && ( cond1c->op == op_eq || cond1c->op == op_neq )
  176.         &&   cond1d->op == op_constant 
  177.         &&   cond1e->op == op_rparen )
  178.         {
  179.             struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
  180.  
  181.             for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
  182.             {
  183.             if ( cond2->op == op_lparen )
  184.             {
  185.                 cond2b = cond2 ->next; if ( cond2b == NULL ) break;
  186.                 cond2c = cond2b->next; if ( cond2c == NULL ) break;
  187.                 cond2d = cond2c->next; if ( cond2d == NULL ) break;
  188.                 cond2e = cond2d->next; if ( cond2e == NULL ) break;
  189.                 cond2f = cond2e->next;
  190.  
  191.                 /* look for match */
  192.                 if ( cond2b->op == op_kvariable
  193.                 &&   cond2b->cfg == cond1b->cfg
  194.                 &&   cond2c->op == cond1c->op
  195.                 &&   cond2d->op == op_constant
  196.                 &&   strcmp( cond2d->str, cond1d->str ) == 0
  197.                 &&   cond2e->op == op_rparen )
  198.                 {
  199.                 /* one of these must be followed by && */
  200.                 if ( cond1f->op == op_and
  201.                 || ( cond2f != NULL && cond2f->op == op_and ) )
  202.                 {
  203.                     /* nuke the first duplicate */
  204.                     cond1 ->op = op_nuked;
  205.                     cond1b->op = op_nuked;
  206.                     cond1c->op = op_nuked;
  207.                     cond1d->op = op_nuked;
  208.                     cond1e->op = op_nuked;
  209.                     if ( cond1f->op == op_and )
  210.                     cond1f->op = op_nuked;
  211.                     else
  212.                     cond2f->op = op_nuked;
  213.                 }
  214.                 }
  215.             }
  216.             }
  217.         }
  218.         }
  219.     }
  220.     }
  221.  
  222.     return cond_list;
  223. }
  224.  
  225.  
  226.  
  227. /*
  228.  * This is the main transformation function.
  229.  */
  230. void fix_conditionals( struct kconfig * scfg )
  231. {
  232.     struct kconfig * cfg;
  233.  
  234.     /*
  235.      * Transform op_variable to op_kvariable.
  236.      */
  237.     transform_to_kvariable( scfg );
  238.  
  239.     /*
  240.      * Transform conditions that use variables from "choice" statements.
  241.      * Choice values appear to the user as a collection of booleans, and the
  242.      * script can test the individual booleans.  But internally, all I have is
  243.      * the N-way value of an unnamed temporary for the whole statement.  So I
  244.      * have to tranform '"$CONFIG_M386" != "y"'
  245.      * into '"$tmpvar_N" != "CONFIG_M386"'.
  246.      */
  247.     for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
  248.     {
  249.     struct condition * cond;
  250.  
  251.     for ( cond = cfg->cond; cond != NULL; cond = cond->next )
  252.     {
  253.         if ( cond->op == op_kvariable && cond->cfg->token == token_choice_item )
  254.         {
  255.         /*
  256.          * Look two more tokens down for the comparison token.
  257.          * It has to be "y" for this trick to work.
  258.          *
  259.          * If you get this error, don't even think about relaxing the
  260.          * strcmp test.  You will produce incorrect TK code.  Instead,
  261.          * look for the place in your Config.in script where you are
  262.          * comparing a 'choice' variable to a value other than 'y',
  263.          * and rewrite the comparison to be '= "y"' or '!= "y"'.
  264.          */
  265.         struct condition * cond2 = cond->next->next;
  266.         const char * label;
  267.  
  268.         if ( strcmp( cond2->str, "y" ) != 0 )
  269.         {
  270.             fprintf( stderr, "tkparse choked in fix_choice_cond\n" );
  271.             exit( 1 );
  272.         }
  273.  
  274.         label = cond->cfg->label;
  275.         cond->cfg  = cond->cfg->cfg_parent;
  276.         cond2->str = strdup( label );
  277.         }
  278.     }
  279.     }
  280.  
  281.     /*
  282.      * Walk the statement list, maintaining a stack of current conditions.
  283.      *   token_if      push its condition onto the stack.
  284.      *   token_else    invert the condition on the top of the stack.
  285.      *   token_endif   pop the stack.
  286.      *
  287.      * For a simple statement, create a condition chain by joining together
  288.      * all of the conditions on the stack.
  289.      */
  290.     {
  291.     struct condition * cond_stack [32];
  292.     int depth = 0;
  293.  
  294.     for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
  295.     {
  296.         switch ( cfg->token )
  297.         {
  298.         default:
  299.         break;
  300.  
  301.         case token_if:
  302.         cond_stack [depth++] = cfg->cond;
  303.         cfg->cond = NULL;
  304.         break;
  305.  
  306.         case token_else:
  307.         {
  308.             /*
  309.              * Invert the condition chain.
  310.              *
  311.              * Be careful to transfrom op_or to op_and1, not op_and.
  312.              * I will need this later in the code that removes
  313.              * duplicate conditions.
  314.              */
  315.             struct condition * cond;
  316.  
  317.             for ( cond  = cond_stack [depth-1];
  318.               cond != NULL;
  319.               cond  = cond->next )
  320.             {
  321.             switch( cond->op )
  322.             {
  323.             default:     break;
  324.             case op_and: cond->op = op_or;   break;
  325.             case op_or:  cond->op = op_and1; break;
  326.             case op_neq: cond->op = op_eq;   break;
  327.             case op_eq:  cond->op = op_neq;  break;
  328.             }
  329.             }
  330.         }
  331.         break;
  332.  
  333.         case token_fi:
  334.         --depth;
  335.         break;
  336.  
  337.         case token_bool:
  338.         case token_choice_item:
  339.         case token_comment:
  340.         case token_define_bool:
  341.         case token_hex:
  342.         case token_int:
  343.         case token_mainmenu_option:
  344.         case token_string:
  345.         case token_tristate:
  346.         cfg->cond = join_condition_stack( cond_stack, depth );
  347.         break;
  348.  
  349.         case token_dep_tristate:
  350.         /*
  351.          * Same as the other simple statements, plus an additional
  352.          * condition for the dependency.
  353.          */
  354.         cond_stack [depth] = cfg->cond;
  355.         cfg->cond = join_condition_stack( cond_stack, depth+1 );
  356.         break;
  357.         }
  358.     }
  359.     }
  360. }
  361.